{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "whjsJasuhstV"
   },
   "source": [
    "<a href=\"https://colab.research.google.com/github/jeffheaton/app_generative_ai/blob/main/t81_559_class_01_4_langchain.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "euOZxlIMhstX"
   },
   "source": [
    "# T81-559: Applications of Generative Artificial Intelligence\n",
    "**Module 1: Course Overview**\n",
    "* Instructor: [Jeff Heaton](https://sites.wustl.edu/jeffheaton/), McKelvey School of Engineering, [Washington University in St. Louis](https://engineering.wustl.edu/Programs/Pages/default.aspx)\n",
    "* For more information visit the [class website](https://sites.wustl.edu/jeffheaton/t81-558/)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "d4Yov72PhstY"
   },
   "source": [
    "# Module 1 Material\n",
    "\n",
    "* Part 1.1: Course Overview [[Video]](https://www.youtube.com/watch?v=OVS-6s20Ms0) [[Notebook]](t81_559_class_01_1_overview.ipynb)\n",
    "* Part 1.2: Generative AI Overview [[Video]](https://www.youtube.com/watch?v=ohmPaSsKhMs) [[Notebook]](t81_559_class_01_2_genai.ipynb)\n",
    "* Part 1.3: Introduction to OpenAI [[Video]](https://www.youtube.com/watch?v=C2xyi2Cq-bU) [[Notebook]](t81_559_class_01_3_openai.ipynb)\n",
    "* **Part 1.4: Introduction to LangChain** [[Video]](https://www.youtube.com/watch?v=qQI5AhaKxuI) [[Notebook]](t81_559_class_01_4_langchain.ipynb)\n",
    "* Part 1.5: Prompt Engineering [[Video]](https://www.youtube.com/watch?v=_Uot1i5sIXo) [[Notebook]](t81_559_class_01_5_prompt_engineering.ipynb)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "AcAUP0c3hstY"
   },
   "source": [
    "# Google CoLab Instructions\n",
    "\n",
    "The following code ensures that Google CoLab is running and maps Google Drive if needed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "xsI496h5hstZ",
    "outputId": "5f629e95-5dc9-4fc9-b4cd-17cce6e1e656"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Note: using Google CoLab\n",
      "Requirement already satisfied: langchain in /usr/local/lib/python3.10/dist-packages (0.1.14)\n",
      "Requirement already satisfied: langchain_openai in /usr/local/lib/python3.10/dist-packages (0.1.1)\n",
      "Requirement already satisfied: PyYAML>=5.3 in /usr/local/lib/python3.10/dist-packages (from langchain) (6.0.1)\n",
      "Requirement already satisfied: SQLAlchemy<3,>=1.4 in /usr/local/lib/python3.10/dist-packages (from langchain) (2.0.29)\n",
      "Requirement already satisfied: aiohttp<4.0.0,>=3.8.3 in /usr/local/lib/python3.10/dist-packages (from langchain) (3.9.3)\n",
      "Requirement already satisfied: async-timeout<5.0.0,>=4.0.0 in /usr/local/lib/python3.10/dist-packages (from langchain) (4.0.3)\n",
      "Requirement already satisfied: dataclasses-json<0.7,>=0.5.7 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.6.4)\n",
      "Requirement already satisfied: jsonpatch<2.0,>=1.33 in /usr/local/lib/python3.10/dist-packages (from langchain) (1.33)\n",
      "Requirement already satisfied: langchain-community<0.1,>=0.0.30 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.0.31)\n",
      "Requirement already satisfied: langchain-core<0.2.0,>=0.1.37 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.1.40)\n",
      "Requirement already satisfied: langchain-text-splitters<0.1,>=0.0.1 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.0.1)\n",
      "Requirement already satisfied: langsmith<0.2.0,>=0.1.17 in /usr/local/lib/python3.10/dist-packages (from langchain) (0.1.40)\n",
      "Requirement already satisfied: numpy<2,>=1 in /usr/local/lib/python3.10/dist-packages (from langchain) (1.25.2)\n",
      "Requirement already satisfied: pydantic<3,>=1 in /usr/local/lib/python3.10/dist-packages (from langchain) (2.6.4)\n",
      "Requirement already satisfied: requests<3,>=2 in /usr/local/lib/python3.10/dist-packages (from langchain) (2.31.0)\n",
      "Requirement already satisfied: tenacity<9.0.0,>=8.1.0 in /usr/local/lib/python3.10/dist-packages (from langchain) (8.2.3)\n",
      "Requirement already satisfied: openai<2.0.0,>=1.10.0 in /usr/local/lib/python3.10/dist-packages (from langchain_openai) (1.16.2)\n",
      "Requirement already satisfied: tiktoken<1,>=0.5.2 in /usr/local/lib/python3.10/dist-packages (from langchain_openai) (0.6.0)\n",
      "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.3.1)\n",
      "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (23.2.0)\n",
      "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.4.1)\n",
      "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (6.0.5)\n",
      "Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.10/dist-packages (from aiohttp<4.0.0,>=3.8.3->langchain) (1.9.4)\n",
      "Requirement already satisfied: marshmallow<4.0.0,>=3.18.0 in /usr/local/lib/python3.10/dist-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (3.21.1)\n",
      "Requirement already satisfied: typing-inspect<1,>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from dataclasses-json<0.7,>=0.5.7->langchain) (0.9.0)\n",
      "Requirement already satisfied: jsonpointer>=1.9 in /usr/local/lib/python3.10/dist-packages (from jsonpatch<2.0,>=1.33->langchain) (2.4)\n",
      "Requirement already satisfied: packaging<24.0,>=23.2 in /usr/local/lib/python3.10/dist-packages (from langchain-core<0.2.0,>=0.1.37->langchain) (23.2)\n",
      "Requirement already satisfied: orjson<4.0.0,>=3.9.14 in /usr/local/lib/python3.10/dist-packages (from langsmith<0.2.0,>=0.1.17->langchain) (3.10.0)\n",
      "Requirement already satisfied: anyio<5,>=3.5.0 in /usr/local/lib/python3.10/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (3.7.1)\n",
      "Requirement already satisfied: distro<2,>=1.7.0 in /usr/lib/python3/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (1.7.0)\n",
      "Requirement already satisfied: httpx<1,>=0.23.0 in /usr/local/lib/python3.10/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (0.27.0)\n",
      "Requirement already satisfied: sniffio in /usr/local/lib/python3.10/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (1.3.1)\n",
      "Requirement already satisfied: tqdm>4 in /usr/local/lib/python3.10/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (4.66.2)\n",
      "Requirement already satisfied: typing-extensions<5,>=4.7 in /usr/local/lib/python3.10/dist-packages (from openai<2.0.0,>=1.10.0->langchain_openai) (4.10.0)\n",
      "Requirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1->langchain) (0.6.0)\n",
      "Requirement already satisfied: pydantic-core==2.16.3 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1->langchain) (2.16.3)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (3.3.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (3.6)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (2.0.7)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests<3,>=2->langchain) (2024.2.2)\n",
      "Requirement already satisfied: greenlet!=0.4.17 in /usr/local/lib/python3.10/dist-packages (from SQLAlchemy<3,>=1.4->langchain) (3.0.3)\n",
      "Requirement already satisfied: regex>=2022.1.18 in /usr/local/lib/python3.10/dist-packages (from tiktoken<1,>=0.5.2->langchain_openai) (2023.12.25)\n",
      "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3.5.0->openai<2.0.0,>=1.10.0->langchain_openai) (1.2.0)\n",
      "Requirement already satisfied: httpcore==1.* in /usr/local/lib/python3.10/dist-packages (from httpx<1,>=0.23.0->openai<2.0.0,>=1.10.0->langchain_openai) (1.0.5)\n",
      "Requirement already satisfied: h11<0.15,>=0.13 in /usr/local/lib/python3.10/dist-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai<2.0.0,>=1.10.0->langchain_openai) (0.14.0)\n",
      "Requirement already satisfied: mypy-extensions>=0.3.0 in /usr/local/lib/python3.10/dist-packages (from typing-inspect<1,>=0.4.0->dataclasses-json<0.7,>=0.5.7->langchain) (1.0.0)\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "try:\n",
    "    from google.colab import drive, userdata\n",
    "    COLAB = True\n",
    "    print(\"Note: using Google CoLab\")\n",
    "except:\n",
    "    print(\"Note: not using Google CoLab\")\n",
    "    COLAB = False\n",
    "\n",
    "# OpenAI Secrets\n",
    "if COLAB:\n",
    "    os.environ[\"OPENAI_API_KEY\"] = userdata.get('OPENAI_API_KEY')\n",
    "\n",
    "# Install needed libraries in CoLab\n",
    "if COLAB:\n",
    "    !pip install langchain langchain_openai"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "pC9A-LaYhsta"
   },
   "source": [
    "# Part 1.4: Introduction to LangChain\n",
    "\n",
    "One of the most intriguing and promising developments in the evolving landscape of language models and artificial intelligence is LangChain. This technology represents a significant leap forward in how we interact with and harness the capabilities of large language models (LLMs). As we delve into the intricacies of LangChain in this chapter, it's important to understand not just the technical underpinnings but also the user experience that makes it so revolutionary.\n",
    "\n",
    "## LangChain Chat Conversation Format\n",
    "\n",
    "To explore LangChain comprehensively, we will adopt a format that has become increasingly familiar and effective in LLMs: the chat conversation interface. This interactive style, reminiscent of how many of us communicate daily, offers a unique and accessible means to illustrate LangChain's capabilities, potential applications, and the nuances of its operation.\n",
    "\n",
    "We begin by importing the components from the LangChain library to support a chat-style interface to OpenAI. We will use the ChatOpenAI interface for the OpenAI family of LLM models."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "id": "K2lC_JK3guaj"
   },
   "outputs": [],
   "source": [
    "# Conversation Style Inteface\n",
    "\n",
    "from langchain_core.messages import HumanMessage, SystemMessage, AIMessage\n",
    "from langchain_core.prompts.chat import (\n",
    "    ChatPromptTemplate,\n",
    "    HumanMessagePromptTemplate,\n",
    "    SystemMessagePromptTemplate,\n",
    ")\n",
    "from langchain_openai import ChatOpenAI"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "YmWHTAub0sTm"
   },
   "source": [
    "The conversation format consists of arrays of chat entries of the following three types:\n",
    "\n",
    "* **SystemMessage** - This class designates the system prompt that provides instructions to the AI on the nature of the conversation and hints and guidelines. Generally, there will be only one system message at the beginning of the array.\n",
    "* **HumanMessage** - This class designates the chat messages from outside the LLM, typically the human user.\n",
    "* **AIMessage** - This class designates the chat messages from the LLM as responses to the HumanMessage messages.\n",
    "\n",
    "Here we see the chain to ask a simple question."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "id": "V_sJoVYAtE6b"
   },
   "outputs": [],
   "source": [
    "messages = [\n",
    "    SystemMessage(\n",
    "        content=\"You are a helpful assistant that concisely and accurately answers questions.\"\n",
    "    ),\n",
    "    HumanMessage(\n",
    "        content=\"What is the capital of France?\"\n",
    "    ),\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "To7rZtUO4B8t"
   },
   "source": [
    "We now submit these messages and retrieve the output from the model. We will use gpt-4o-mini, which is good enough for this query. Further, we use a zero temperature; we are simply looking for a factual answer, and creativity is not a goal or concern."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Xfb875JhtI6J",
    "outputId": "f4e120de-7a83-4b82-e10c-d8c3f990322b"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model response:\n",
      "The capital of France is Paris.\n",
      "-----------\n",
      "{'token_usage': {'completion_tokens': 7, 'prompt_tokens': 30, 'total_tokens': 37}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}\n"
     ]
    }
   ],
   "source": [
    "MODEL = 'gpt-4o-mini'\n",
    "\n",
    "# Initialize the OpenAI LLM with your API key\n",
    "llm = ChatOpenAI(\n",
    "  model=MODEL,\n",
    "  temperature= 0.0,\n",
    "  n= 1,\n",
    "  max_tokens= 256)\n",
    "\n",
    "print(\"Model response:\")\n",
    "output = llm.invoke(messages)\n",
    "print(output.content)\n",
    "print(\"-----------\")\n",
    "print(output.response_metadata)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "be6a0hXj4lHj"
   },
   "source": [
    "The model that LangChain returns to you returns additional metadata. This data shows the token usage, which might be useful for estimating the total cost expected from this query.\n",
    "\n",
    "We can continue to grow this conversation if we wish. To do so, we added the model's response and another human question. Here, we will ask the model if it was sure about its last response."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "2vJuMVHZ1jJ8",
    "outputId": "d34c6945-9d2b-41c4-8e02-33b5056a72d9"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SystemMessage : You are a helpful assistant that concisely and accurately.\n",
      "HumanMessage : What is the capital of France?\n",
      "AIMessage : The capital of France is Paris.\n",
      "HumanMessage : Are you sure, I think it was renamed for some reason?\n"
     ]
    }
   ],
   "source": [
    "messages.append(output)\n",
    "messages.append(HumanMessage(content=\"Are you sure, I think it was renamed for some reason?\"))\n",
    "for message in messages:\n",
    "    print(f\"{type(message).__name__} : {message.content}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "A8Z7DZRH5TFr"
   },
   "source": [
    "We can submit the conversation array to the model and see its latest response."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "9qFxkEmAz1w1",
    "outputId": "f1928a10-db7f-4abc-92af-23e24cd8ecb6"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model response:\n",
      "Yes, I am sure. The capital of France is still Paris.\n"
     ]
    }
   ],
   "source": [
    "print(\"Model response:\")\n",
    "output = llm.invoke(messages)\n",
    "print(output.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Y9nvX9oA3a0Z"
   },
   "source": [
    "## Asking a Single Question\n",
    "\n",
    "If you wish to ask the model a single question, not as part of a conversation chain, you can pass a string to the model for a response."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 35
    },
    "id": "34-95k0qg8ss",
    "outputId": "5d93f5a9-1ba6-4b52-d3ec-a4a8fa76451f"
   },
   "outputs": [
    {
     "data": {
      "application/vnd.google.colaboratory.intrinsic+json": {
       "type": "string"
      },
      "text/plain": [
       "'1. New York City, New York\\n2. Los Angeles, California\\n3. Chicago, Illinois\\n4. Houston, Texas\\n5. Phoenix, Arizona'"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# complete\n",
    "\n",
    "from langchain_openai import OpenAI, ChatOpenAI\n",
    "\n",
    "MODEL = 'gpt-4o-mini'\n",
    "\n",
    "# Initialize the OpenAI LLM (Language Learning Model) with your API key\n",
    "llm = ChatOpenAI(model=MODEL, temperature=0)\n",
    "\n",
    "# Define the question\n",
    "question = \"What are the five largest cities in the USA by population?\"\n",
    "\n",
    "# Use Langchain to call the OpenAI API\n",
    "# The method and parameters might differ based on the Langchain version\n",
    "response = llm.invoke(question)\n",
    "\n",
    "# Print the response\n",
    "display(response.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "_o2EkUkN3hEX"
   },
   "source": [
    "## Prompt Templates\n",
    "\n",
    "LangChain allows you to create chains of operations typically performed as part of an LLM-enabled application. One of these operations is a prompt template, which allows you to insert text into a previously created prompt. In this example, we will create a prompt template that asks the model to create a random blog post title.\n",
    "\n",
    "```\n",
    "Return only the title of a blog post article title on the topic of {topic} in {language}\n",
    "```\n",
    "\n",
    "To accomplish this objective, we will use a **PromptTemplate** object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "L-g3zOXBmulc",
    "outputId": "fb7a08ec-2f47-4526-9605-c0116289334f"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.10/dist-packages/langchain_core/_api/deprecation.py:117: LangChainDeprecationWarning: The function `run` was deprecated in LangChain 0.1.0 and will be removed in 0.2.0. Use invoke instead.\n",
      "  warn_deprecated(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mReturn only the title of a blog post article title on the topic of pets for data scientists in english\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\"Using Data Science to Improve Pet Health and Wellness\"\n"
     ]
    }
   ],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "from langchain.chains import LLMChain, SimpleSequentialChain\n",
    "\n",
    "topic = \"pets for data scientists\"\n",
    "language = \"english\"\n",
    "\n",
    "# Initialize the OpenAI LLM (Language Learning Model) with your API key\n",
    "# Use higher temperature for greater creativity\n",
    "llm = ChatOpenAI(model=MODEL, temperature=0.7)\n",
    "\n",
    "title_template = PromptTemplate( input_variables = ['topic', 'language'],\\\n",
    "  template = 'Return only the title of a blog post article title on the topic of {topic} in {language}' )\n",
    "title_chain = LLMChain(llm=llm, prompt=title_template, verbose=True)\n",
    "response = title_chain.run({'topic':topic,'language':language })\n",
    "print(response)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "IOpAcj-byBPg"
   },
   "source": [
    "## Create a Simple Sequential Chain\n",
    "\n",
    "We will now use LangChain to tie multiple LLM calls into a longer chain using the **SimpleSequentialChain** class. We will use two smaller chains to create a title and body text for a blog post. We begin by defining the two prompts we will use to construct this blog post. Also, note that we request that the LLM utilize [markdown](https://en.wikipedia.org/wiki/Markdown) to generate the actual blog post.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "id": "ELS-9JD3Sao6"
   },
   "outputs": [],
   "source": [
    "# Create the two prompt templates\n",
    "title_template = PromptTemplate( input_variables = ['topic'], template = 'Give me a blog post title on {topic} in English' )\n",
    "article_template = PromptTemplate( input_variables = ['title'], template = 'Write a blog post for {title}, format in markdown.' )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "k3vy7jf3-_xl"
   },
   "source": [
    "We will create the first chain to generate the random title. Here, we allow the user to specify the topic. We use a higher temperature to increase the creativity of the title. We also use a simpler model to minimize cost for the relatively simple task of title selection."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "id": "_KV8UJUDyP8M"
   },
   "outputs": [],
   "source": [
    "MODEL = 'gpt-4o-mini'\n",
    "\n",
    "# Create a chain to generate a random\n",
    "llm = ChatOpenAI(model=MODEL, temperature=0.7)\n",
    "title_chain = LLMChain(llm=llm, prompt=title_template, verbose=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "cO0ielMf_xRa"
   },
   "source": [
    "Next, we compose the actual blog post; we will use a lower temperature to decrease creativity and cause the LLM to stick to factual information and avoid hallucinations. We also use a more complex model to provide a better article."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "id": "G7OCQCggyHlB"
   },
   "outputs": [],
   "source": [
    "MODEL2 = 'gpt-4'\n",
    "\n",
    "# Create the article chain\n",
    "llm2 = ChatOpenAI(model=MODEL2, temperature=0.1)\n",
    "article_chain = LLMChain(llm=llm2, prompt=article_template, verbose=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "6rftFvMyBa4-"
   },
   "source": [
    "Now, we combine these two chains into one. The input to the first chain will be the selected topic. The first chain will then output the title to the second chain, which will, in turn, output the actual article."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "id": "2ibHBt4eyKZt"
   },
   "outputs": [],
   "source": [
    "# Create a complete chain to create a new blog post\n",
    "complete_chain=SimpleSequentialChain(chains=[title_chain, article_chain], verbose=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "V_7P-n_DBvpD"
   },
   "source": [
    "We can now display the final article. In this case, we requested an article on \"photography,\" and displayed the final article's markdown."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "mwro_kfKXvml",
    "outputId": "d0118b4d-9c33-4882-8d5a-0fe4eb42ad59"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new SimpleSequentialChain chain...\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mGive me a blog post title on photography in English\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\u001b[36;1m\u001b[1;3m\"Capturing Moments: The Art of Photography\"\u001b[0m\n",
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3mWrite a blog post for \"Capturing Moments: The Art of Photography\", format in markdown.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\u001b[33;1m\u001b[1;3m# Capturing Moments: The Art of Photography\n",
      "\n",
      "Photography is more than just clicking a button on a camera. It's an art form that captures moments, emotions, and stories in a single frame. It's about seeing the world from a different perspective and sharing that vision with others. In this blog post, we will delve into the art of photography and how it allows us to capture and preserve our most precious moments.\n",
      "\n",
      "## The Power of a Photograph\n",
      "\n",
      "A photograph has the power to evoke emotions, recall memories, and tell a story without uttering a single word. It's a snapshot of a moment in time, forever frozen for us to revisit whenever we please. Whether it's a breathtaking landscape, a candid moment of joy, or a poignant scene of hardship, a photograph can transport us to that moment, allowing us to experience the emotions and sensations associated with it.\n",
      "\n",
      "## The Art of Capturing Moments\n",
      "\n",
      "The art of photography lies in the ability to capture these moments. It's about more than just having the right equipment or knowing the technical aspects of how a camera works. It's about observing the world around you, understanding the interplay of light and shadow, and having the patience to wait for the perfect moment.\n",
      "\n",
      "### Observation\n",
      "\n",
      "Observation is a key skill in photography. It's about noticing the details that others might overlook - the way the light filters through the leaves, the expression on a person's face, or the patterns formed by a flock of birds in the sky. By paying attention to these details, you can capture a unique perspective that tells a story.\n",
      "\n",
      "### Understanding Light\n",
      "\n",
      "Light is one of the most important elements in photography. It can dramatically change the mood and atmosphere of a photograph. By understanding how light works and how to manipulate it, you can create stunning images that evoke a range of emotions.\n",
      "\n",
      "### Patience\n",
      "\n",
      "Patience is often overlooked in photography, but it's crucial for capturing the perfect moment. Sometimes, you need to wait for the right lighting conditions, for the perfect expression, or for the decisive moment when everything comes together. It's this patience that often separates a good photograph from a great one.\n",
      "\n",
      "## The Joy of Photography\n",
      "\n",
      "Photography is a rewarding hobby and profession. It allows us to express our creativity, capture our memories, and share our perspective with the world. Whether you're a professional photographer or a hobbyist, the joy of capturing a moment and preserving it in a photograph is a feeling that never gets old.\n",
      "\n",
      "In conclusion, photography is a powerful art form that allows us to capture and preserve our most precious moments. It requires observation, understanding of light, and patience, but the rewards are well worth it. So, pick up your camera, start observing the world around you, and capture the moments that matter to you.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "from IPython.display import display_markdown\n",
    "\n",
    "article = complete_chain.invoke('photography')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "h1pN8CbXCE6F"
   },
   "source": [
    "The actual display of the markdown is handled by this code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 677
    },
    "id": "Vt5uGJawuru_",
    "outputId": "7ff949a4-294f-43fb-afb7-7785aa22b673"
   },
   "outputs": [
    {
     "data": {
      "text/markdown": [
       "# Capturing Moments: The Art of Photography\n",
       "\n",
       "Photography is more than just clicking a button on a camera. It's an art form that captures moments, emotions, and stories in a single frame. It's about seeing the world from a different perspective and sharing that vision with others. In this blog post, we will delve into the art of photography and how it allows us to capture and preserve our most precious moments.\n",
       "\n",
       "## The Power of a Photograph\n",
       "\n",
       "A photograph has the power to evoke emotions, recall memories, and tell a story without uttering a single word. It's a snapshot of a moment in time, forever frozen for us to revisit whenever we please. Whether it's a breathtaking landscape, a candid moment of joy, or a poignant scene of hardship, a photograph can transport us to that moment, allowing us to experience the emotions and sensations associated with it.\n",
       "\n",
       "## The Art of Capturing Moments\n",
       "\n",
       "The art of photography lies in the ability to capture these moments. It's about more than just having the right equipment or knowing the technical aspects of how a camera works. It's about observing the world around you, understanding the interplay of light and shadow, and having the patience to wait for the perfect moment.\n",
       "\n",
       "### Observation\n",
       "\n",
       "Observation is a key skill in photography. It's about noticing the details that others might overlook - the way the light filters through the leaves, the expression on a person's face, or the patterns formed by a flock of birds in the sky. By paying attention to these details, you can capture a unique perspective that tells a story.\n",
       "\n",
       "### Understanding Light\n",
       "\n",
       "Light is one of the most important elements in photography. It can dramatically change the mood and atmosphere of a photograph. By understanding how light works and how to manipulate it, you can create stunning images that evoke a range of emotions.\n",
       "\n",
       "### Patience\n",
       "\n",
       "Patience is often overlooked in photography, but it's crucial for capturing the perfect moment. Sometimes, you need to wait for the right lighting conditions, for the perfect expression, or for the decisive moment when everything comes together. It's this patience that often separates a good photograph from a great one.\n",
       "\n",
       "## The Joy of Photography\n",
       "\n",
       "Photography is a rewarding hobby and profession. It allows us to express our creativity, capture our memories, and share our perspective with the world. Whether you're a professional photographer or a hobbyist, the joy of capturing a moment and preserving it in a photograph is a feeling that never gets old.\n",
       "\n",
       "In conclusion, photography is a powerful art form that allows us to capture and preserve our most precious moments. It requires observation, understanding of light, and patience, but the rewards are well worth it. So, pick up your camera, start observing the world around you, and capture the moments that matter to you."
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "output_key = complete_chain.output_key\n",
    "\n",
    "display_markdown(article[output_key], raw=True)"
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "anaconda-cloud": {},
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3.11 (genai)",
   "language": "python",
   "name": "genai"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
